package com.lagou.seckill.common.utils;

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.MapType;
import com.lagou.seckill.common.enums.ErrorCodeEnum;
import com.lagou.seckill.common.exceptions.CustomException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Description: JSON序列化
 */
@Slf4j
public class JSONUtils {
	private JSONUtils(){
		throw new CustomException.ServiceException(ErrorCodeEnum.SYSTEM_ERROR_B0801);
	}

	private static ObjectMapper objectMapper = new ObjectMapper();
	
	private static ObjectMapper objectMapperNonNull = new ObjectMapper();
	
	static {
		objectMapperNonNull.setSerializationInclusion(Include.NON_NULL);
		objectMapperNonNull.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
		objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
		objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
	}

	/**
	 * @Description: 将json字符串读为java对象
	 */
	public static <T> T read(String content, Class<T> valueType) {
		try {
			return objectMapper.readValue(content, valueType);
		} catch (Exception e) {
			throw new CustomException.ServiceException(ErrorCodeEnum.SYSTEM_ERROR_B1001,e);
		}
	}
	
	/**
	 * @Description: 将json字符串读为java对象,支持复杂泛型
	 */
	public static <T> T read(String content, TypeReference<T> valueTypeRef) {
		try {
			return objectMapper.readValue(content, valueTypeRef);
		} catch (Exception e) {
			throw new CustomException.ServiceException(ErrorCodeEnum.SYSTEM_ERROR_B1001,e);
		}
	}
	
	/**
	 * @Description: 将json字符串读为java对象集合
	 */
	public static <T> List<T> readList(String content, Class<T> valueType) {
		try {
			JavaType javaType = objectMapper.getTypeFactory().constructParametricType(List.class, valueType);
			return objectMapper.readValue(content, javaType);
		} catch (Exception e) {
			throw new CustomException.ServiceException(ErrorCodeEnum.SYSTEM_ERROR_B1001,e);
		}
	}

	/**
	 * @Description: 将json字符串读为java对象集合
	 */
	public static <T> List<T> optList(String content, Class<T> valueType) {
		if(StringUtils.isEmpty(content)){
			return new ArrayList<>();
		}
		try {
			JavaType javaType = objectMapper.getTypeFactory().constructParametricType(List.class, valueType);
			return objectMapper.readValue(content, javaType);
		} catch (Exception e) {
			throw new CustomException.ServiceException(ErrorCodeEnum.SYSTEM_ERROR_B1001,e);
		}
	}
	
	/**
	 * @Description: 反序列化为Map
	 * @version 2.2.0
	 */
	public static Map<Object,Object> readAsMap(String content) {
		return read(content, Map.class);
	}
	
	/**
	 * 读取节点
	 * @param content
	 * @return
	 */
	public static JsonNode readTree(String content) {
		try {
			return objectMapper.readTree(content);
		} catch (IOException e) {
			throw new CustomException.ServiceException(ErrorCodeEnum.SYSTEM_ERROR_B1001,e);
		}
	}
	
	/**
	 * @Description: 将java对象写为json字符串
	 */
	public static String write(Object value) {
		try {
			return objectMapper.writeValueAsString(value);
		} catch (JsonProcessingException e) {
			throw new CustomException.ServiceException(ErrorCodeEnum.SYSTEM_ERROR_B1001,e);
		}
	}
	
	public static String writeExcludeNull(Object value) {
		try {
			return objectMapperNonNull.writeValueAsString(value);
		} catch (JsonProcessingException e) {
			throw new CustomException.ServiceException(ErrorCodeEnum.SYSTEM_ERROR_B1001,e);
		}
	}

	public static String writeList(List<?> value) {
		if(value==null||value.isEmpty()){
			return null;
		}
		try {
			return objectMapper.writeValueAsString(value);
		} catch (JsonProcessingException e) {
			throw new CustomException.ServiceException(ErrorCodeEnum.SYSTEM_ERROR_B1001,e);
		}
	}
	public static boolean isJson(String json) {
		try {
			objectMapper.readTree(json);
			return true;
		} catch (Exception e) {
			log.error("jackson check json error, json: {}", json, e);
			return false;
		}
	}

	/**
	 * JSON反序列化（Map）
	 */
	public static Map<String, Object> fromMap(String json) {
		if (json == null) {
			return null;
		}
		try {
			MapType mapType = objectMapper.getTypeFactory().constructMapType(HashMap.class, String.class, Object.class);
			return objectMapper.readValue(json, mapType);
		} catch (IOException e) {
			log.error("jackson from error, json: {}", json, e);
			throw new RuntimeException("jackson from error, json: "+json, e);
		}
	}

}
